#include "libcard.h"

#define MAX_BUF_SIZE		512

static pthread_mutex_t MUTEX_OPER = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_t* card_mutex = NULL;
pthread_cond_t cond;//条件变量
pthread_t pthread_id;
int stae_flag;//状态标志 0待机 1打开射频 2激活卡片 3操作卡片  关闭射频时将flag置0x02

typedef struct {
	rf_card* card;
	int uart_fd;
}card_t;

card_t g_card;

int uart_send(const int fd, const uint8 *buf, uint8 len)
{
	int sended = 0;
	int i;

	if(fd <= 0) 	return -1;
	if(NULL == buf)	return -1;
	if(len <= 0)	return -1;

	pthread_mutex_lock(&MUTEX_OPER);

	sended = write(fd, buf, len);	

	if( sended <= 0) {
		printf("##libcard##--Port send [%d] error.\n ", sended);
	}
	/*
	   printf("SEND LPDU[%03d] -->", sended);
	   for(i=0; i < sended; i++) {
	   printf("%02x ", buf[i]);
	   }
	   printf("\n");
	 */
	pthread_mutex_unlock(&MUTEX_OPER);

	return sended;
}

int uart_recv(const int fd, uint8 *buf, int rlen)
{
	int len = 0;
	int i;
	if(fd <= 0) 	return -1;
	if(NULL == buf)	return -1;

	pthread_mutex_lock(&MUTEX_OPER);
	len = read(fd, buf, rlen);
	pthread_mutex_unlock(&MUTEX_OPER);

	return len;
}

int listen_recv(const int fd, char *buf, int rlen, int timeout)
{
	int len = 0;
	int count =0;
	int ret;
	int i = 0;
	fd_set fdset;

	struct timeval tm;

	if (fd < 0 || rlen<0 || rlen> MAX_BUF_SIZE)
	{
		printf(" ##libcard## param err !\n");
		return -1;
	}

	pthread_mutex_lock(&MUTEX_OPER);
	tm.tv_sec = timeout/1000;
	tm.tv_usec = (timeout%1000)*1000;
	while(count<3)	//while(count<4)
	{
		FD_ZERO(&fdset);
		FD_SET(fd, &fdset);

		ret = select(fd + 1, &fdset, NULL, NULL, &tm);
		if(ret < 0)
		{
			perror("##libcard##select failued !\n ");
			//printf("--select failued !\n");
			break;
		}
		else if(ret == 0)
		{
			//printf("--select timeout !\n");
			++count;
		}
		else if(FD_ISSET(fd, &fdset))
		{
			len = read(fd, buf, rlen);
			break;
		}
	}
	pthread_mutex_unlock(&MUTEX_OPER);
	/*
	   printf("RECV DATA[%d]:-->",len);
	   for(i=0; i<len; i++)
	   printf("%02x ",buf[i]);
	   printf("\n");
	 */
	return len;
}


int port_open(uart_para *port)
{
	int fd = 0;
	uart_para *com = port;

	if(NULL == com)	return -1;

	//打开串口设备
	fd = open(com->name, O_RDWR|O_NOCTTY|O_NONBLOCK);
	if(fd < 0) {
		printf("##libcard##--Open PORT: [%s] failure.\n", com->name);
	}
	return fd;
}

int speed_to_flag(int speed)
{
	int i;
	int cnt = 0;

	for (i = 0; i < sizeof(speed_arr)/sizeof(int); i++) {
		cnt = (speed - speed_arr[i]);
		//printf("cnt = %d\n", cnt);
		if ( cnt == 0) 
			return baudflag_arr[i];
		//else
		//printf("speed_arr[%d] = %d\n", i, speed_arr[i]);
	}

	printf("##libcard##--Unsupported baudrate, use 9600 instead!\n");
	return B9600;
}

int port_setup(int fd, uart_para *port)
{
	uart_para *com = port;
	struct termios old_tio, new_tio;
	int baud_rate = 0;

	if(fd < 0)		return -1;
	if(NULL == com)		return -1;

	tcgetattr(fd, &old_tio);
	bzero(&new_tio, sizeof(struct termios));
	new_tio.c_cflag |= (CLOCAL | CREAD);

	//设置波特率
	baud_rate = speed_to_flag(com->baud);
	new_tio.c_cflag |= baud_rate; 
	//设置停止位
	switch(com->stop_bits) {
		case 1:
			new_tio.c_cflag &= ~CSTOPB;
			break;
		case 2:
			new_tio.c_cflag |= CSTOPB;
			break;
		default:
			printf("##libcard##--PORT stop bits set error. use default.\n");
			new_tio.c_cflag &= ~CSTOPB;
			break;
	}

	//设置奇偶校验
	switch(com->parity) {
		case 0://无校验
			new_tio.c_cflag &= ~PARENB;
			break;
		case 1://奇校验
			new_tio.c_cflag |= (PARENB | PARODD);
			break;
		case 2://偶校验
			new_tio.c_cflag |= PARENB;
			new_tio.c_cflag &= ~PARODD;
			break;
		case 3://MARK校验
			new_tio.c_cflag |= (PARENB | PARODD);
			new_tio.c_cflag |= CMSPAR;
			break;
		case 4://SPACE校验
			new_tio.c_cflag |= PARENB;
			new_tio.c_cflag &= ~PARODD;
			new_tio.c_cflag |= CMSPAR;
			break;
		default:
			printf("##libcard##--PORT parity set error. use default.\n");
			new_tio.c_cflag &= ~PARENB;
			break;
	}
	new_tio.c_cflag &= ~CSIZE;
	switch(com->data_bits) {
		case 5:
			new_tio.c_cflag |= CS5;
			break;
		case 6:
			new_tio.c_cflag |= CS6;
			break;
		case 7:
			new_tio.c_cflag |= CS7;
			break;
		case 8:
			new_tio.c_cflag |= CS8;
			break;
		default:
			printf("##libcard##--PORT data bits set error. use default.\n");
			new_tio.c_cflag |= CS8;
			break;
	}

	//设置无硬件流控
	new_tio.c_cflag &= ~CRTSCTS;
	new_tio.c_lflag = 0;
	new_tio.c_oflag = 0;
	new_tio.c_cc[VMIN] = 1;
	new_tio.c_cc[VTIME] = 0;
	new_tio.c_iflag &= ~(IXON | IXOFF | IXANY);

	cfsetispeed(&new_tio, baud_rate);
	cfsetospeed(&new_tio, baud_rate);
	tcsetattr(fd, TCSANOW, &new_tio);
	tcflush(fd, TCIFLUSH);

	return 0;
}

void setTimer(unsigned int seconds, unsigned int mseconds)
{
	struct timeval temp;  

	temp.tv_sec = seconds + (mseconds/1000);  
	temp.tv_usec = (mseconds%1000)*1000;  

	select(0, NULL, NULL, NULL, &temp);  

	return ;  
}

//检查版本,同时检测读卡器的通信是否断开
void* protocol_check_ver(void* arg)
{
	int len = 0;
	uint8 cmd[] = {0x02,0x00,0x02,0x31,0x11,0x20,0x03};
	uint8 data[255];
	static int err_count = 0;

	while(1)
	{
		memset(data,0,sizeof(data));
		pthread_mutex_lock(card_mutex);

		if(stae_flag != 0)//如果读卡器正在进行其他操作暂时不进行版本检查
		{
			pthread_cond_wait(&cond,card_mutex);
		}

		if((uart_send(g_card.uart_fd, cmd, sizeof(cmd))) < 0)
		{
			printf("##libcard## check version send error\n");
			g_card.card->errcode = 1;//通信异常
			pthread_mutex_unlock(card_mutex);
			setTimer(1,0);
			continue;
		}

		len = listen_recv(g_card.uart_fd, data, sizeof(data),1000);
		if(len <= 0){
			printf("##libcard## check card version listen_recv timeout or error!\n");
			g_card.card->errcode = 1;//通信异常
			pthread_mutex_unlock(card_mutex);
			continue;
		}

		if((data[0] != 0x02) || (data[3] != 0x00) || (data[4] != 0x00)){
			if(err_count > 5){
				printf("##libcard## check version , card reponse error!\n");
				g_card.card->errcode = 1;//连续5次检查版本失败，通信异常
				err_count = 0;
			}

			err_count++;
			pthread_mutex_unlock(card_mutex);
			continue;
		}
		g_card.card->errcode = 0;//通信异常
		pthread_mutex_unlock(card_mutex);
//		printf("=====check version ok !\n");
		err_count = 0;
		setTimer(1,0);
	}

	return NULL;
}

//初始化函数，pcard指向一个rf_card结构， plock指向pthread_mutex_t互斥量, 指向sem_t信号量,在检测到刷卡时置位。//返回0成功，1 失败
int protocol_card_init(void * pcard, void *plock, void *psem) 
{
	int fd = 0;

	if(pcard == NULL)
	{
		printf("##libcard error##pcard is NULL!\n");
	}
	if(plock == NULL)
	{
		printf("##libcard error##plock is NULL!\n");
		return 1;
	}

	if(psem == NULL)
	{
		printf("##libcard error## psem is NULL!\n");
		return 1;
	}


	g_card.card = (rf_card*)pcard;
	card_mutex = (pthread_mutex_t*)plock;
	stae_flag = 0;//初始化待机
	pthread_cond_init(&cond,NULL);

	if((fd = port_open(&(g_card.card->com))) == -1 )
	{
		printf("##libcard error## open device fail\n");
		return 1;
	}

	g_card.uart_fd = fd;
	port_setup(g_card.uart_fd,&(g_card.card->com));
	pthread_create(&pthread_id,NULL,protocol_check_ver,NULL);

	printf("uart name:%s uart baud:%d uart data_bit:%d uart parity:%d uart stop_bits:%d",g_card.card->com.name, g_card.card->com.baud,
			g_card.card->com.data_bits, g_card.card->com.parity, g_card.card->com.stop_bits);

	printf("uart fd is:%d\n",g_card.uart_fd);

	return 0;
}

//关闭函数，释放资源
int protocol_card_close()//返回0成功，1 失败
{
	int kill_rc = 0;

	kill_rc = pthread_kill(pthread_id,0);//判断现程的状态
	if(kill_rc == ESRCH)
		printf("##libcard## the specified thread did not exists or already quit\n");
	else if(kill_rc == EINVAL)
		printf("##libcard##signal is invalid\n");
	else
	{
		printf("##libcard##the specified thread is alive\n");
		// retval = pthread_join();
		// pthread_exit();
	}

	free(g_card.card);
	pthread_mutex_destroy(card_mutex);
	pthread_cond_destroy(&cond);

	return 0;
}
int  protocol_led_ctrl(void)
{
	int err;
	int len;

	uint8 cmd[] = {0x02,0x00,0x03,0x31,0x14,0xC0,0xE5,0x03};
	uint8 data[255];

	memset(data,0,sizeof(data));

	pthread_mutex_lock(card_mutex);
	uart_send(g_card.uart_fd, cmd, sizeof(cmd));
	len = listen_recv(g_card.uart_fd, data, sizeof(data), 1000);
	if((len < 0) || (data[3] != 0) || (data[4] != 0))
	{
		pthread_mutex_unlock(card_mutex);
		printf("##libcard## ctrl led fail\n");
		return 1;
	}
	stae_flag = 0;//流程标示待机
	printf("##libcard## ctrl led success\n");
	pthread_mutex_unlock(card_mutex);
	return 0;


}
//打开射频
int protocol_open_rf(void)
{
	int err;
	int len;

	uint8 cmd[] = {0x02,0x00,0x02,0x31,0x90,0xA1,0x03};
	uint8 data[255];
	memset(data,0,sizeof(data));

	pthread_mutex_lock(card_mutex);

	uart_send(g_card.uart_fd,cmd,sizeof(cmd));


	len = listen_recv(g_card.uart_fd, data, sizeof(data), 1000);
	if((len < 0) || (data[3] != 0) || (data[4] != 0))
	{
		pthread_mutex_unlock(card_mutex);
		printf("##libcard## open rf fail\n");
		return 1;//打开射频失败
	}
	stae_flag = 1;//流程标示待机
	printf("##libcard## open rf success\n");
	pthread_mutex_unlock(card_mutex);
	return 0;
}

//关闭射频
int protocol_close_rf(void)
{
	int err;
	int len;

	uint8 cmd[] = {0x02,0x00,0x02,0x31,0x91,0xA0,0x03};
	uint8 data[255];
	memset(data,0,sizeof(data));

	pthread_mutex_lock(card_mutex);

	uart_send(g_card.uart_fd, cmd, sizeof(cmd));

	len = listen_recv(g_card.uart_fd,data,sizeof(data),1000);
	if((len < 0) || (data[3] != 0) || (data[4] != 0))
	{
		printf("##libcard## close rf fail\n");

		pthread_mutex_unlock(card_mutex);
		protocol_led_ctrl();
		stae_flag = 0;//流程标示待机
		pthread_cond_signal(&cond);	
		return 1;//关闭射频失败
	}

	stae_flag = 0;//流程标示待机
	printf("##libcard## close rf success\n");
	pthread_mutex_unlock(card_mutex);
	protocol_led_ctrl();

	pthread_cond_signal(&cond);	

	return 0;
}

//激活卡函数，delaytime 等待时间，cardtype 返回的卡类型，UIDLen返回的卡号长度，cardUID指向一个32字节大小的内存，用于存储返回的卡号。
int protocol_enabled_card(short delaytime, char *cardtype, unsigned char *UIDLen, char * cardUID) //返回0成功，1 失败
{
	int err;
	int count = 0;
	uint8 cmd[] = {0x02,0x00,0x04,0x32,0x24,0x00,0xC3,0xD5,0x03};
	uint8 data[255];
	uint8 hex[2];
	int len = 0, index = 0;
	unsigned int delay = (unsigned int)delaytime;

	memcpy(hex,&delay,sizeof(delay));//将十进制转化为16进制  本机为小端存储
	cmd[5]= hex[1];
	cmd[6] = hex[0];
	cmd[7] = cmd[3]^cmd[4]^cmd[5]^cmd[6];//异或校验

	printf("##libcard## begin enable card...\n");
	while(count < 60)//如果连续60次没有探测到卡则退出
	{
		memset(data,0,sizeof(data));
		pthread_mutex_lock(card_mutex);
		if((uart_send(g_card.uart_fd,cmd,sizeof(cmd))) < 0 )
		{
			printf("##libcard## enable card  send error\n");
			pthread_mutex_unlock(card_mutex);
			count++;
			setTimer(0,delay);
			continue;
		}

		if((len = listen_recv(g_card.uart_fd, data, sizeof(data), 1000) < 0))
		{
			printf("##libcard## enable card  recv error\n");
			pthread_mutex_unlock(card_mutex);
			count++;
			setTimer(0,delay);
			continue;
		}

		if(data[3] == 0x30 &&  data[4] == 0x06)//等待卡进入感应区超时
		{
			printf("##libcard## wait card enter induction zone outtime count=%d\n",count);			
			pthread_mutex_unlock(card_mutex);
			count++;
			setTimer(0,delay);
			continue;
		}
		else if(data[3] == 0x30 && data[4] == 0x05)//激活失败
		{
			printf("##libcard## enable card fail!!!\n");
			pthread_mutex_unlock(card_mutex);
			return 1;
		}
		else if(data[3] == 0x00 && data[4] == 0x00)//激活成功
		{


			printf("##libcard## enable card success.\n");

			g_card.card->cardtype = data[5];
			*cardtype = data[5];

			*UIDLen = data[6];
			g_card.card->UIDLen = data[6];

			for(index=0; index<data[6]; index++){
				cardUID[index] = data[7+index];
				g_card.card->cardUID[index] = data[7+index];
			}

			printf("##libcard## card_type:%x UIDLen=%x cardUID:",*cardtype,*UIDLen);
			for(index=0; index<data[6]; index++)
				printf("%x ", *(cardUID + index));
			printf("\n");
			pthread_mutex_unlock(card_mutex);
			return 0;
		}
		pthread_mutex_unlock(card_mutex);
	}
	if(count >= 120)
	{
		printf("##libcard## enable card fail count > 120!!!\n");
		//pthread_mutex_unlock(card_mutex);
		return 1;
	}
}


//读卡查询函数，money 返回卡余额，locknum 返回灰锁次数。
int protocol_read_card(float *money, char *locknum) //返回0成功，1 失败
{
	short delaytime = 250;
	int recLen = 0;
	int i = 0, j = 0;
	unsigned char cardtype[1];
	unsigned char UIDLen[1];
	unsigned char cardUID[255];
	/*对读卡器ESAM操作*/
	unsigned char cmd_1[] = {0x02,0x00,0x0A,0x32,0x26,0xFF,0x00,0xA4,0x00,0x00,0x02,0xDF,0x02,0x90,0x03};
	unsigned char cmd_2[] = {0x02,0x00,0x08,0x32,0x26,0xFF,0x00,0xB0,0x95,0x18,0x04,0xD2,0x03};
	unsigned char cmd_3[] = {0x02,0x00,0x08,0x32,0x26,0xFF,0x00,0xB0,0x85,0x00,0x15,0xCB,0x03};
	unsigned char cmd_4[] = {0x02,0x00,0x0B,0x32,0x26,0xFF,0x00,0x20,0x00,0x00,0x03,0x12,0x34,0x56,0xB8,0x03};
	unsigned char cmd_5[] = {0x02,0x00,0x08,0x32,0x26,0xFF,0xE0,0xCA,0x00,0x00,0x27,0xE6,0x03};
	unsigned char cmd_6[] = {0x02,0x00,0x08,0x32,0x26,0xFF,0xE0,0xCC,0x00,0x00,0x07,0xC0,0x03};
	unsigned char data[255];

	protocol_open_rf();


	if(protocol_enabled_card(delaytime,cardtype,UIDLen,cardUID) == 1){
		printf("##libcard## read card money fail ,due to enable card fail\n");	
		protocol_close_rf();
		return 1;
	}
	else
	{
		//对ESAM第一次操作
		if(uart_send(g_card.uart_fd, cmd_1, sizeof(cmd_1)) < 0){ 
			printf("##libcard## read card send cmd_1 error\n");	
			protocol_close_rf();
			return 1;
		}

		memset(data,0,sizeof(data));
		setTimer(0,delaytime);
		recLen = listen_recv(g_card.uart_fd, data, sizeof(data), 1000);
		if((recLen <= 0) || (data[0] != 0x02)){
			printf("##libcard## read card recv data_1 error\n");
			protocol_close_rf();
			return 1;
		}
		else
		{
			for(i=0; i<recLen;i++)
				if((data[i]==0x9F) && (data[i+1]==0x0C))//查找FCI
					break;
			i += 3;
			g_card.card->ver = data[i+9]; //保存密匙版本
			//for(j=0; j<10; j++)
			//	g_card.card->cardNUM[j] = data[i+10+j];//保存用户卡卡号

			//for(j=0; j<4; j++)
			//card_info->card_handle_date[j] = data[i+20+j];//保存办充电卡理日期
		}

		//对ESAM第二次操作
		if(uart_send(g_card.uart_fd, cmd_2, sizeof(cmd_2)) < 0){
			printf("##libcard## read card send cmd_2 error\n");
			protocol_close_rf();			
			return 1;
		}

		memset(data, 0, sizeof(data));
		setTimer(0,delaytime);
		recLen = listen_recv(g_card.uart_fd, data, sizeof(data), 1000);
		if((recLen <= 0) || (data[0] != 0x02)){
			printf("##libcard## read card recv data_2 error\n");
			protocol_close_rf();
			return 1;
		}
		else 
		{
			//for(i=0; i<4; i++)
			//	card_info->card_vailed_data[i] = data[i+5];//保存用户卡的有效期
			;
		}

		//对ESAM第三次操作
		if(uart_send(g_card.uart_fd, cmd_3, sizeof(cmd_3)) < 0){
			printf("##libcard## read card send cmd_3 error\n");	
			protocol_close_rf();
			return 1;
		}
		memset(data,0,sizeof(data));
		setTimer(0,delaytime);
		recLen = listen_recv(g_card.uart_fd, data, sizeof(data),1000);
		if((recLen <= 0) || (data[0] != 0x02)){
			printf("##libcard## read card recv data_3 error\n");
			protocol_close_rf();
			return 1;
		}
		else
		{
			for(i=0; i<8; i++)
				g_card.card->cardNUM[i] = data[i+6];//保存支付卡卡号
			;
		}

		//对ESAM第四次操作
		if(uart_send(g_card.uart_fd, cmd_4, sizeof(cmd_4)) < 0)
			printf("##libcard## read card send cmd_4 error\n");		
		memset(data,0,sizeof(data));
		setTimer(0,delaytime);
		if(listen_recv(g_card.uart_fd, data, sizeof(data),1000) < 0)
			printf("##libcard## read card recv data_4 error\n");
		else		
			;	

		if(uart_send(g_card.uart_fd, cmd_5, sizeof(cmd_5)) < 0)//对ESAM第五次操作
			printf("##libcard## read card send cmd_5 error\n");		
		memset(data,0,sizeof(data));
		setTimer(0,delaytime);
		recLen = listen_recv(g_card.uart_fd, data, sizeof(data), 1000);
		if((recLen <= 0) || (data[0] != 0x02)){
			printf("##libcard## read card recv data_5 error\n");
			protocol_close_rf();
			return 1;
		}
		else		
		{
			if((data[recLen-4] == 0x69) && (data[recLen-3] == 0x85))//如果没有异常灰锁			
			{
				//card_info->card_err_locknum = 0;//保存灰锁次数
				;
			}
			else if((data[recLen-4] == 0x90) && (data[recLen-3] == 0x00))//如果卡片被锁过
			{
				//	card_info->card_frozen_amount = ((data[5]<<24) | (data[6]<<16) | (data[7]<<8) | data[8]);
				//	card_info->card_frozen_amount = card_info->card_frozen_amount / 100;//保存冻结卡内余额

				//保存卡内ET余额
				g_card.card->available_money = ((data[12]<<24) | (data[13]<<16) | (data[14]<<8) | data[15]);
				//card_info->ET_balance = card_info->ET_balance / 100;//保存卡内ET余额

				//for(i=0; i<4; i++)
				//	card_info->card_ET_balance[i] = data[12+i];//保存ET余额

				//for(i=0; i<2; i++)
				//	card_info->card_ET_tran_serial_num[i] = data[16+i];//保存卡内ET交易序号

				//for(i=0; i<4; i++)
				//	card_info->last_tran_date[i] = data[24+i];//保存上次交易日期

				//for(i=0; i<3; i++)
				//	card_info->last_tran_time[i] = data[28+i];//保存上次交易时间

				//card_info->card_err_locknum = data[recLen-5];//保存异常灰锁次数
			}			
		}

		if(uart_send(g_card.uart_fd, cmd_6, sizeof(cmd_6)) < 0)//对ESAM第六次操作
			printf("##libcard## read card send cmd_6 error\n");		
		memset(data,0,sizeof(data));
		setTimer(0,delaytime);
		if((recLen = listen_recv(g_card.uart_fd,data,sizeof(data), 1000)) < 0)
			printf("##libcard## read card recv data_6 error\n");
		else		
		{
			//card_info->card_money = ((data[5]<<24) | (data[6]<<16) | (data[7]<<8) | data[8]);
			//card_info->card_money = card_info->card_money / 100;//保存冻结卡内余额
			;
		}
	}

	protocol_close_rf();
	*money = g_card.card->available_money;
	//*locknum = card_info->card_err_locknum;
	printf("############ Card Info ##################\n");
	printf("card.type = %x\n",g_card.card->cardtype);
	printf("card.UIDLen = %d\n",g_card.card->UIDLen);

	printf("card.cardUID = ");
	for(i=0; i<g_card.card->UIDLen; i++)
		printf("%02x ", g_card.card->cardUID[i]);
	printf("\n");

	printf("card.cardNUM = ");
	for(i=0; i<8; i++)
		printf("%02x",g_card.card->cardNUM[i]);
	printf("\n");
	printf("card.ver = %02x\n",g_card.card->ver);
	printf("card.money = %d\n",g_card.card->available_money);
	printf("############    Card  ##################\n");

		return 0;
}














